package org.alwayssuper.protostar.schema;

import org.alwayssuper.protostar.PrepareLoadStrategy;
import org.alwayssuper.protostar.Schema;
import org.alwayssuper.protostar.field.BasicField;
import org.alwayssuper.protostar.util.KeyValuePair;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Map.Entry;

/**
 * 多键值对Schema，用于处理key后面直接跟value对象的协议格式
 * 每个valueSchema自行决定读取多少字节，适用于GBT32960等协议
 * @author alwaysSuper
 */
public abstract class MultiMapSchema<K, V> extends BasicField<Entry<K, V>> {

    public final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
    public final Schema<K> keySchema;
    public final Map<K, Schema> valueSchema;

    public MultiMapSchema(Schema<K> keySchema) {
        this.keySchema = keySchema;
        PrepareLoadStrategy<K> loadStrategy = new PrepareLoadStrategy<>();
        addSchemas(loadStrategy);
        this.valueSchema = loadStrategy.build();
    }

    protected abstract void addSchemas(PrepareLoadStrategy<K> schemaRegistry);

    @Override
    public KeyValuePair<K, V> readFrom(ByteBuf input) {
        K key = keySchema.readFrom(input);
        KeyValuePair<K, V> result = new KeyValuePair<>(key);

        // 根据键找到对应的Schema，让其自行决定读取多少字节
        Schema<V> schema = valueSchema.get(key);
        if (schema != null) {
            V value = schema.readFrom(input);
            result.setValue(value);
        } else {
            // 如果没有找到对应的Schema，读取剩余所有字节作为byte[]
            byte[] bytes = new byte[input.readableBytes()];
            input.readBytes(bytes);
            result.setValue((V) bytes);
            log.warn("未找到键[{}]对应的Schema，已读取剩余{}字节", key, bytes.length);
        }
        return result;
    }

    @Override
    public void writeTo(ByteBuf output, Entry<K, V> entry) {
        if (entry == null)
            return;
            
        K key = entry.getKey();
        V value = entry.getValue();
        
        // 写入键
        keySchema.writeTo(output, key);

        // 根据键找到对应的Schema写入值
        Schema<V> schema = valueSchema.get(key);
        if (schema != null) {
            schema.writeTo(output, value);
        } else {
            // 如果值是字节数组，直接写入
            if (value instanceof byte[]) {
                output.writeBytes((byte[]) value);
            } else {
                log.warn("未注册的信息:KEY[{}], VALUE[{}]", key, value);
            }
        }
    }

    @Override
    public KeyValuePair<K, V> readFrom(ByteBuf input, int length) {
        // 对于有限长度的读取，需要控制读取范围
        int readerLength = input.readerIndex() + length;
        int writerIndex = input.writerIndex();
        input.writerIndex(readerLength);
        
        KeyValuePair<K, V> result = readFrom(input);
        
        input.setIndex(readerLength, writerIndex);
        return result;
    }

    @Override
    public void writeTo(ByteBuf output, int length, Entry<K, V> entry) {
        int writerLength = output.writerIndex() + length;
        writeTo(output, entry);
        output.writerIndex(writerLength);
    }
}